/**
 *  Copyright 2012 Rafal Korytkowski
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.googlecode.rapidjunit.launcher;

import java.util.HashSet;
import java.util.Set;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants;
import org.eclipse.jdt.junit.launcher.JUnitLaunchShortcut;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorPart;

import com.googlecode.rapidjunit.RapidJUnit;
import com.googlecode.rapidjunit.finder.JUnitEngine;

/**
 * Launches JUnits that are binded with the given class.
 * 
 * @author Rafal Korytkowski
 */
public class RapidJUnitLauncher extends JUnitLaunchShortcut {
	
	/**
	 * Id under which the RapidJUnit launch shortcut has been registered.
	 */
	public static final String LAUNCH_SHORTCUT_ID = "com.googlecode.rapidjunit.launcher.RapidJUnitLauncher";
	
	/**
	 * @see org.eclipse.jdt.junit.launcher.JUnitLaunchShortcut#launch(org.eclipse.ui.IEditorPart,
	 *      java.lang.String)
	 */
	@Override
	public void launch(IEditorPart editor, String mode) {
		ITypeRoot selected = JavaUI.getEditorInputTypeRoot(editor.getEditorInput());
		
		if (selected instanceof IJavaElement) {
			launch((IJavaElement) selected, mode);
		} else if (selected instanceof IAdaptable) {
			IJavaElement element = (IJavaElement) ((IAdaptable) editor).getAdapter(IJavaElement.class);
			launch(element, mode);
		}
	}
	
	@Override
	public void launch(ISelection selection, String mode) {
		if (!(selection instanceof IStructuredSelection)) {
			return;
		}
		
		Object[] elements = ((IStructuredSelection) selection).toArray();
		if (elements.length < 1) {
			return;
		}
		
		Object selected = elements[0];
		if (selected instanceof IJavaElement) {
			launch((IJavaElement) selected, mode);
		} else if (selected instanceof IAdaptable) {
			IJavaElement element = (IJavaElement) ((IAdaptable) selected).getAdapter(IJavaElement.class);
			launch(element, mode);
		}
		
	}
	
	private void launch(IJavaElement selected, String mode) {
		ILaunchConfigurationWorkingCopy config;
		ILaunchConfiguration[] configs;
		IType type = null;
		
		try {
			if (selected instanceof IJavaProject) {
				IJavaProject project = (IJavaProject) selected;
				configs = getLaunchConfigurations(new StructuredSelection(project));
				if (configs.length != 0) {
					config = configs[0].getWorkingCopy();
				} else {
					config = createLaunchConfiguration(project);
				}
			} else if (selected instanceof ICompilationUnit) {
				ICompilationUnit element = (ICompilationUnit) selected;
				type = element.findPrimaryType();
				configs = getLaunchConfigurations(new StructuredSelection(type.getJavaProject()));
				if (configs.length != 0) {
					config = configs[0].getWorkingCopy();
				} else {
					config = createLaunchConfiguration(type.getJavaProject());
				}
			} else {
				return;
			}
			
			config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_KEEPRUNNING, true);
			config.doSave();
		}
		catch (CoreException e) {
			RapidJUnit.log(e);
			return;
		}
		
		Set<IType> tests = new HashSet<IType>();
		if (type != null) {
			if (JUnitEngine.isJUnit(type)) {
				tests.add(type);
			} else {
				//tests = RapidJUnit.getManager().getTestCases(type);
			}
		}
		
		boolean rerun = false;
		
		if (!tests.isEmpty()) {
			try {
				for (IType test : tests) {
					rerun = TestsRerunQueue.getInstance().queueTest(test);
					if (!rerun) {
						break;
					}
				}
				TestsRerunQueue.getInstance().run();
			}
			catch (Exception e) {
				RapidJUnit.log(e);
			}
		} else {
			TestsRerunQueue.getInstance().stopCurrentSession();
		}
		
		if (!rerun) {
			if (!tests.isEmpty()) {
				StringBuilder classnames = new StringBuilder("-classnames ");
				for (IType test : tests) {
					classnames.append(test.getFullyQualifiedName() + " ");
				}
				
				String args = "";
				try {
					args = config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, "");
				}
				catch (CoreException e) {
					RapidJUnit.log(e);
				}
				
				config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, args + classnames.toString());
			}
			
			final ILaunchConfiguration launchConfig = config;
			final String launchMode = mode;
			
			Display.getDefault().asyncExec(new Runnable() {
				
				@Override
				public void run() {
					DebugUITools.launch(launchConfig, launchMode);
				}
			});
		}
	}
	
	@Override
	protected String getLaunchConfigurationTypeId() {
		return RapidJUnitLaunchConfigurationDelegate.LAUNCH_CONFIGURATION_ID;
	}
}
